package com.yuntsg.ruiijn.controller.system;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.yuntsg.ruiijn.JiaXinZhi.JiaXinZhiIndexController;
import com.yuntsg.ruiijn.database.entity.*;
import com.yuntsg.ruiijn.database.mapper.*;
import com.yuntsg.ruiijn.entity.PageInfo;
import com.yuntsg.ruiijn.paperana.test.FirstStart;
import com.yuntsg.ruiijn.paperana.utils.StrUtils;
import common.sysconfig.MinioConfig;
import common.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import static com.yuntsg.ruiijn.JiaXinZhi.InfoGetRuleName.getRuleName;
import static com.yuntsg.ruiijn.JiaXinZhi.JiaXinZhiIndexController.readArticleTable;
import static com.yuntsg.ruiijn.JiaXinZhi.JiaXinZhiIndexController.readFundTable;

@SuppressWarnings("ALL")
@Component
@Slf4j
public class InitController implements CommandLineRunner {

    private final String unitTable = "unit_dept";
    private final String unknownTable = "unknown_dept";
    private final String dataTable = "wos_basic";
    private final String fundTable = "check_fund";
    public Map<Integer, Map<String, String>> infoAndRuleMap = new HashMap<>();
    public Map<Integer, Map<String, Integer>> deptNameMap = new HashMap<>();
    public Set<String> pmidSet = new HashSet<>();
    public Map<Integer, Map<Integer, List<String>>> idAndFundListMap = new HashMap<>();
    public Map<Integer, List<JiaXinZhiIndexController.ArticleInfo>> articleInfoList = new HashMap<>();
    public List<String> unitRuleFile = new ArrayList<>();
    public List<String> fundRuleFile = new ArrayList<>();
    @Autowired
    private CheckFundMapper fundMapper;
    @Autowired
    private UnitDeptMapper unitDeptMapper;
    @Autowired
    private WosBasicMapper wosBasicMapper;
    @Autowired
    private MinioUtil minioUtil;
    @Autowired
    private MinioConfig prop;
    @Autowired
    private SysQueenMapper sysQueenMapper;
    @Autowired
    private UnitBasicMapper unitBasicMapper;
    @Autowired
    private UnknownDeptMapper unknownDeptMapper;
    @Autowired
    private
    @Resource
    FirstStart firstStart;

    // 读取规则文件
    public static List<String> getRuleFile(String filePath) {
        List<String> rule = new ArrayList<>();
        List<String> list = FileUtil.readLines(filePath, "utf-8");
        for (String s : list) {
            String[] split = s.split("_");
            if (split.length == 3) {
                rule.add(s);
            }
        }
        return rule;
    }

    @Override
    public void run(String... args) throws Exception {
        if (VerifyUtil.isServer()) {
            firstStart.CheckFirstStart();
            if (!StrUtils.isRuiJin()) {
                String fundTable = "check_fund";
                String articleTable = "wos_basic";
                System.out.println("开始加载第-1项:判断基础文件模板等信息在不在路径下");
                System.out.println("开始第一项:判断单位列表是否有本单位的基础数据,如果没有增加基本科室信息表与未知科室信息表");
                checkFundDeptUnknowDept();
                System.out.println("开始第二项:读取所有单位的科室信息和未知科室信息");
                infoAndRuleMap = CheckFirstUnit.getUnitRule(unitTable, unknownTable);
                System.out.println("开始加载第三项:读取各自单位的科室信息规则,以后上传WOS数据的时候根据第一作者和通讯作者的部门信息设置单篇文章属于哪个部门");
                List<UnitBasic> unitList = unitBasicMapper.selectList(null);
                for (UnitBasic unitBasic : unitList) {
                    Map<String, Integer> deptNameSet = new HashMap<>();
                    for (UnitDept unitDept : new LambdaQueryChainWrapper<>(unitDeptMapper).select(UnitDept::getDept, UnitDept::getId).eq(UnitDept::getGid, unitBasic.getId()).list()) {
                        deptNameSet.put(unitDept.getDept(), unitDept.getId());
                    }
                    deptNameMap.put(unitBasic.getId(), deptNameSet);
                }
                System.out.println("开始加载第四项:读取撤稿的PMID的集合,在WOS入库的时候由程序判断");
                List<String> list = FileUtil.readLines("2023_07_08_PubMed_retracted_list_35531.txt", "UTF-8");
                pmidSet.addAll(list);
                System.out.println("开始加载第五项:规范基金信息");
                add_fund();
                idAndFundListMap = readFundTable(fundTable, "id", "ids`,`old_name`,`gid`,`cn_name`,`new_name");
                System.out.println("开始加载第六项:读取基金信息");
                articleInfoList = readArticleTable(articleTable, "id", "gid`,`dept_name`,`c_py`,`co_flag`,`so_type`,`rp_flag`,`copy_flag`,`withdraw_flag", idAndFundListMap);
                System.out.println("开始加载第七项:获取标准单位信息");
                unitRuleFile = getRuleFile("unitRuleFile_2023_07_14.txt");
                System.out.println("开始加载第八项:获取标准基金信息" + unitRuleFile.size());
                fundRuleFile = getRuleFile("fundRuleFile_2023_07_14.txt");
                System.out.println("开始加载第九项:初始化MINIO_UTIL");
                minioUtil.makeBucketPolicy(prop.getBucketName());
                System.out.println("第九项minio:" + prop.getBucketName() + "加载完成");
                System.out.println("开始加载第十项:将重启之前正在分析的数据恢复成待分析状态");
                List<SysQueen> queenList = new LambdaQueryChainWrapper<>(sysQueenMapper).eq(SysQueen::getStatus, -1).list();
                for (SysQueen sysQueen : queenList) {
                    sysQueen.setStatus(0);
                    sysQueenMapper.updateById(sysQueen);
                }
                System.out.println("第十项恢复分析状态表完成___" + fundRuleFile.size());
            }
        }
        System.out.println("开始加载第十二项:重置Rid");
        rid();
        System.out.println("项目初始化完成" + DateUtil.now());

    }

    /**
     * 循环单位表 如果没有对应的数据,则增加自己的数据
     */
    public void checkFundDeptUnknowDept() {
        unitBasicMapper.selectList(null).parallelStream().forEach(i -> {
            Integer gid = i.getId();
            Long count = Long.valueOf(new LambdaQueryChainWrapper<>(unitDeptMapper).eq(UnitDept::getGid, gid).count());
            if (count == 0) {
                System.out.println("准备新增" + gid + "单位的UNIT_DEPT数据");
                List<UnitDept> list = new LambdaQueryChainWrapper<>(unitDeptMapper).eq(UnitDept::getGid, 1).list();
                for (UnitDept unitDept : list) {
                    unitDept.setId(null);
                    unitDept.setGid(gid);
                    unitDeptMapper.insert(unitDept);
                }
            }

            Long unknowCount = Long.valueOf(new LambdaQueryChainWrapper<>(unknownDeptMapper).eq(UnknownDept::getGid, gid).count());
            if (unknowCount == 0) {
                System.out.println("准备新增" + gid + "单位的UN_KNOW_UNIT_DEPT数据");
                List<UnknownDept> list = new LambdaQueryChainWrapper<>(unknownDeptMapper).eq(UnknownDept::getGid, 1).list();
                for (UnknownDept unknownDept : list) {
                    unknownDept.setId(null);
                    unknownDept.setGid(gid);
                    unknownDeptMapper.insert(unknownDept);
                }
            }
//            System.out.println("完成单位:" + gid);
        });

    }

    public void check_fund() throws Exception {

        List<Entity> unit_list = Db.use().query("select * from unit_basic ");


        unit_list.parallelStream().forEach(i -> {
            Integer gid = i.getInt("id");
//            System.out.println("规范基金时候的单位___" + gid);
            /**
             * 初始化数据
             */
            int from = 1;
            int max = 0;
            List<Entity> tableNum = null;
            try {
                tableNum = Db.use().query("select count(1) as count from " + dataTable + " where gid = " + gid + " ; ");
            } catch (SQLException e) {
                e.printStackTrace();
            }
            System.out.println("读表长度为:" + tableNum.get(0).getInt("count"));
            int count = tableNum.get(0).getInt("count");
            if (count > 0) {
                try {
                    max = Db.use().queryNumber("select max(id) from " + dataTable).intValue();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            Integer onePageNum = 1000;
            int page = max / onePageNum;
            if (max % onePageNum != 0) {
                page++;
            }
            System.out.println("总页数___" + page);
            List<PageInfo> pageInfos = new ArrayList<>();
            for (int e = 1; e <= page; e++) {
                int start = (e - 1) * onePageNum + from;
                int stop = e * onePageNum + from - 1;
                if (stop > max) {
                    stop = max + onePageNum;
                }
                pageInfos.add(new PageInfo(start, stop));
            }
            Map<String, List<Integer>> map = new ConcurrentHashMap<>();
            pageInfos.forEach(pg -> {
                List<WosBasic> list = new LambdaQueryChainWrapper<>(wosBasicMapper).eq(WosBasic::getGid, gid).eq(WosBasic::getSoType, 1)/*这里只看WOS的数据*/.between(WosBasic::getId, pg.getFrom(), pg.getTo()).list();
                for (WosBasic wosBasic : list) {
                    List<String> fuList = new ArrayList<>();
                    String cFu = wosBasic.getCFu();
                    if (!StringUtil.isEmpty(cFu)) {
                        String[] fuArry = cFu.split("; ");
                        for (String fuOne : fuArry) {
                            fuOne = (fuOne.indexOf("[") > 0) ? fuOne.substring(0, fuOne.indexOf("[")).trim() : fuOne;
                            fuList.add(fuOne);
                            if (map.containsKey(fuOne)) {
                                List<Integer> idList = map.get(fuOne);
                                idList.add(wosBasic.getId());
                                map.put(fuOne, idList);
                            } else {
                                ArrayList<Integer> idList = new ArrayList<>();
                                idList.add(wosBasic.getId());
                                map.put(fuOne, idList);
                            }
                        }
                        wosBasic.setFundList(JSONObject.toJSONString(fuList));
                        wosBasicMapper.updateById(wosBasic);
                    }
                }
            });
            for (Map.Entry<String, List<Integer>> entry : map.entrySet()) {
                String key = entry.getKey();
                List<Integer> value = entry.getValue();
                CheckFund checkFund = new CheckFund();
                if (!StringUtil.isEmpty(key) && !key.trim().equals("")) {
                    CheckFund one = new LambdaQueryChainWrapper<>(fundMapper).eq(CheckFund::getGid, gid).eq(CheckFund::getOldName, key).one();
                    if (one != null) {
                        one.setIds(JSONObject.toJSONString(value));
                        one.setCount(value.size());
                        fundMapper.updateById(one);
                    } else {
                        checkFund.setGid(gid);
                        checkFund.setOldName(key);
                        checkFund.setCnName(YouDaoTransLate.DoEnToCnTrans(key));
                        checkFund.setCount(value.size());
                        checkFund.setNewName(getRuleName(key, fundRuleFile));
                        checkFund.setIds(JSONObject.toJSONString(value));
                        checkFund.setUploadTime(LocalDateTime.now());
                        fundMapper.insert(checkFund);
                    }
                }
            }

        });

    }

    public void add_fund() throws Exception {

        List<Entity> unit_list = Db.use().query("select * from unit_basic ");

        for (Entity entity : unit_list) {

            Integer gid = entity.getInt("id");

//            System.out.println("规范基金时候的单位___" + gid);
            /**
             * 初始化数据
             */
            int from = 1;
            int max = 0;
            List<Entity> tableNum = null;
            try {
                tableNum = Db.use().query("select count(1) as count from " + fundTable + " where gid = " + gid + " ; ");
            } catch (SQLException e) {
                e.printStackTrace();
            }
//            System.out.println("读表长度为:" + tableNum.get(0).getInt("count"));
            int count = tableNum.get(0).getInt("count");
            if (count == 0) {
                try {
                    max = Db.use().queryNumber("select max(id) from " + dataTable).intValue();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            } else {
                continue;
            }
            Integer onePageNum = 1000;
            int page = max / onePageNum;
            if (max % onePageNum != 0) {
                page++;
            }
            System.out.println("总页数___" + page);
            List<PageInfo> pageInfos = new ArrayList<>();
            for (int e = 1; e <= page; e++) {
                int start = (e - 1) * onePageNum + from;
                int stop = e * onePageNum + from - 1;
                if (stop > max) {
                    stop = max + onePageNum;
                }
                pageInfos.add(new PageInfo(start, stop));
            }
            Map<String, List<Integer>> map = new ConcurrentHashMap<>();
            pageInfos.stream().parallel().forEach(pg -> {
                List<WosBasic> list = new LambdaQueryChainWrapper<>(wosBasicMapper).eq(WosBasic::getGid, gid).eq(WosBasic::getSoType, 1)/*这里只看WOS的数据*/.between(WosBasic::getId, pg.getFrom(), pg.getTo()).list();
                for (WosBasic wosBasic : list) {
                    List<String> fuList = new ArrayList<>();
                    String cFu = wosBasic.getCFu();
                    if (!StringUtil.isEmpty(cFu)) {
                        String[] fuArry = cFu.split("; ");
                        for (String fuOne : fuArry) {
                            fuOne = (fuOne.indexOf("[") > 0) ? fuOne.substring(0, fuOne.indexOf("[")).trim() : fuOne;
                            fuList.add(fuOne);
                            if (map.containsKey(fuOne)) {
                                List<Integer> idList = map.get(fuOne);
                                idList.add(wosBasic.getId());
                                map.put(fuOne, idList);
                            } else {
                                ArrayList<Integer> idList = new ArrayList<>();
                                idList.add(wosBasic.getId());
                                map.put(fuOne, idList);
                            }
                        }
                        wosBasic.setFundList(JSONObject.toJSONString(fuList));
                        wosBasicMapper.updateById(wosBasic);
                    }
                }
            });
            for (Map.Entry<String, List<Integer>> entry : map.entrySet()) {
                String key = entry.getKey();
                List<Integer> value = entry.getValue();
                CheckFund checkFund = new CheckFund();
                if (!StringUtil.isEmpty(key) && !key.trim().equals("")) {
                    CheckFund one = new LambdaQueryChainWrapper<>(fundMapper).eq(CheckFund::getGid, gid).eq(CheckFund::getOldName, key).one();
                    if (one != null) {
                        one.setIds(JSONObject.toJSONString(value));
                        one.setCount(value.size());
                        fundMapper.updateById(one);
                    } else {
                        checkFund.setGid(gid);
                        checkFund.setOldName(key);
                        checkFund.setCnName(YouDaoTransLate.DoEnToCnTrans(key));
                        checkFund.setCount(value.size());
                        checkFund.setNewName(getRuleName(key, fundRuleFile));
                        checkFund.setIds(JSONObject.toJSONString(value));
                        checkFund.setUploadTime(LocalDateTime.now());
                        fundMapper.insert(checkFund);
                    }
                }
            }
        }


    }

    /**
     * 恢复RID
     */
    public void rid() {
        List<WosBasic> list = new LambdaQueryChainWrapper<>(wosBasicMapper)
                .select(WosBasic::getId, WosBasic::getRid, WosBasic::getAnalysisMap, WosBasic::getSoType)
                .eq(WosBasic::getSoType, 1)
                .isNull(WosBasic::getRid)
                .isNotNull(WosBasic::getAnalysisMap)
                .list();
        System.out.println("需要处理的list有" + list.size());
        for (WosBasic wosBasic : list) {
            try {
                String analysisMap = wosBasic.getAnalysisMap();
                Map<Integer, Integer> map = JSONObject.parseObject(analysisMap, Map.class);
                Integer integer = map.get(1);
                wosBasic.setRid(integer);
                wosBasicMapper.updateById(wosBasic);
            } catch (Exception e) {

            }
        }
    }

}
